#include<iostream>
#include <stdio.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
using namespace std;
#define Info 0
#define Debug 1
#define Warning 2
#define Error 3
#define Fatal 4

#define screen 1
#define Onefile 2
#define Classifyfile 3
#define Logfile "log.txt"
class Log
{
public:
    Log()
    {
        _printMethod = screen; // 打印的地方
        _path = "./log/";      // 打印的路径
    }

    //更换打印地方
    void Enable(int Method)
    {
        _printMethod=Method;
    }

    string LeveltoString(int level)
    {
        switch (level)
        {
        case Info:return "Info";
            break;
        case Debug:return "Debug";
            break;
        case Warning:return "Warning";
            break;
        case Error:return "Error";
            break;
        case Fatal:return "Fatal";
            break;
        default:break;
        }
    }
    // log(Fatal, "error string: %s, error code: %d", strerror(errno), errno);
    // 打印出对应信息到对应文件
    void operator()(int level, char *format, ...)
    {
        //获取时间放到左边
        time_t t=time(nullptr);
        struct tm*ctime=localtime(&t);
        char leftbuffer[1024];
        //格式化输出多个变量到指定输出流
        snprintf(leftbuffer,sizeof(leftbuffer),"[%s]-%d年-%d月-%d日-%d时-%d分-%d秒"
        ,LeveltoString(level).c_str(),ctime->tm_year+1900,ctime->tm_mon+1,ctime->tm_mday,ctime->tm_hour,ctime->tm_min,ctime->tm_sec);

        //将其他信息放在右边
        char rightbuffer[1024];
        va_list s;
        va_start(s,format);
        //vsnprintf打印可变长度参数列表
        vsnprintf(rightbuffer,sizeof(rightbuffer),format,s);
        va_end(s);

        //合并两个字符串
        char logtxt[2*1024];
        snprintf(logtxt, sizeof(logtxt), "%s %s\n", leftbuffer, rightbuffer);

        //打印字符串(为了分类打印到不同文件中，多传入一个参数)
        //cout<<logtxt<<endl;
        Printlog(level,logtxt);
    }
    //logtxt时是临时对象(将亡值)，可以使用右值引用，提高效率
    //使用const string&接收 ：??
    void Printlog(int level, const string &txt)
    {
        //1.打印到屏幕
        //2.打印到一个文件
        //3.打印到多个文件
        switch(_printMethod)
        {
        case screen: cout<<txt;
            break;
        case Onefile:PrintOnefile(Logfile,txt);
            break;
        case Classifyfile:PrintClassifyfile(level,txt);
            break;
        default:  
            break;
        }

    }
    //
    void PrintOnefile(const string& filename,const string &txt)
    {
        string name=_path;
        name+=filename;
    
        int fd=open(name.c_str(),O_RDWR|O_CREAT|O_APPEND,0666);
        if(fd<0)
        {
            perror("open");
            return;
        }
        write(fd,txt.c_str(),txt.size());
        close(fd);
    }
    
    void PrintClassifyfile(int level,const string &txt)
    {
        string filename=LeveltoString(level)+"."+"txt";

        PrintOnefile(filename,txt);
    }

    
    
private:
    int _printMethod;
    string _path;
};